1   /*
2    * Copyright (C) 2005 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import static com.google.common.base.CharMatcher.WHITESPACE;
20  import static com.google.common.collect.Lists.newArrayList;
21  
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.collect.ImmutableSet;
24  import com.google.common.testing.EqualsTester;
25  
26  import junit.framework.AssertionFailedError;
27  import junit.framework.TestCase;
28  
29  import java.io.Serializable;
30  import java.util.ArrayList;
31  import java.util.Arrays;
32  import java.util.Collection;
33  import java.util.Collections;
34  import java.util.Iterator;
35  import java.util.List;
36  
37  /**
38   * Unit test for {@link Predicates}.
39   *
40   * @author Kevin Bourrillion
41   */
42  @GwtCompatible(emulated = true)
43  public class PredicatesTest extends TestCase {
44    private static final Predicate<Integer> TRUE = Predicates.alwaysTrue();
45    private static final Predicate<Integer> FALSE = Predicates.alwaysFalse();
46    private static final Predicate<Integer> NEVER_REACHED =
47        new Predicate<Integer>() {
48      @Override
49      public boolean apply(Integer i) {
50        throw new AssertionFailedError(
51            "This predicate should never have been evaluated");
52      }
53    };
54  
55    /** Instantiable predicate with reasonable hashCode() and equals() methods. */
56    static class IsOdd implements Predicate<Integer>, Serializable {
57      private static final long serialVersionUID = 0x150ddL;
58      @Override
59      public boolean apply(Integer i) {
60        return (i.intValue() & 1) == 1;
61      }
62      @Override public int hashCode() {
63        return 0x150dd;
64      }
65      @Override public boolean equals(Object obj) {
66        return obj instanceof IsOdd;
67      }
68      @Override public String toString() {
69        return "IsOdd";
70      }
71    }
72  
73    /**
74     * Generates a new Predicate per call.
75     *
76     * <p>Creating a new Predicate each time helps catch cases where code is
77     * using {@code x == y} instead of {@code x.equals(y)}.
78     */
79    private static IsOdd isOdd() {
80      return new IsOdd();
81    }
82  
83    /*
84     * Tests for Predicates.alwaysTrue().
85     */
86  
87    public void testAlwaysTrue_apply() {
88      assertEvalsToTrue(Predicates.alwaysTrue());
89    }
90  
91    public void testAlwaysTrue_equality() throws Exception {
92      new EqualsTester()
93          .addEqualityGroup(TRUE, Predicates.alwaysTrue())
94          .addEqualityGroup(isOdd())
95          .addEqualityGroup(Predicates.alwaysFalse())
96          .testEquals();
97    }
98  
99    /*
100    * Tests for Predicates.alwaysFalse().
101    */
102 
103   public void testAlwaysFalse_apply() throws Exception {
104     assertEvalsToFalse(Predicates.alwaysFalse());
105   }
106 
107   public void testAlwaysFalse_equality() throws Exception {
108     new EqualsTester()
109         .addEqualityGroup(FALSE, Predicates.alwaysFalse())
110         .addEqualityGroup(isOdd())
111         .addEqualityGroup(Predicates.alwaysTrue())
112         .testEquals();
113   }
114 
115   /*
116    * Tests for Predicates.not(predicate).
117    */
118 
119   public void testNot_apply() {
120     assertEvalsToTrue(Predicates.not(FALSE));
121     assertEvalsToFalse(Predicates.not(TRUE));
122     assertEvalsLikeOdd(Predicates.not(Predicates.not(isOdd())));
123   }
124 
125   public void testNot_equality() {
126     new EqualsTester()
127         .addEqualityGroup(Predicates.not(isOdd()), Predicates.not(isOdd()))
128         .addEqualityGroup(Predicates.not(TRUE))
129         .addEqualityGroup(isOdd())
130         .testEquals();
131   }
132 
133   public void testNot_equalityForNotOfKnownValues() {
134     new EqualsTester()
135         .addEqualityGroup(TRUE, Predicates.alwaysTrue())
136         .addEqualityGroup(FALSE)
137         .addEqualityGroup(Predicates.not(TRUE))
138         .testEquals();
139 
140     new EqualsTester()
141         .addEqualityGroup(FALSE, Predicates.alwaysFalse())
142         .addEqualityGroup(TRUE)
143         .addEqualityGroup(Predicates.not(FALSE))
144         .testEquals();
145 
146     new EqualsTester()
147         .addEqualityGroup(Predicates.isNull(), Predicates.isNull())
148         .addEqualityGroup(Predicates.notNull())
149         .addEqualityGroup(Predicates.not(Predicates.isNull()))
150         .testEquals();
151 
152     new EqualsTester()
153         .addEqualityGroup(Predicates.notNull(), Predicates.notNull())
154         .addEqualityGroup(Predicates.isNull())
155         .addEqualityGroup(Predicates.not(Predicates.notNull()))
156         .testEquals();
157   }
158 
159   /*
160    * Tests for all the different flavors of Predicates.and().
161    */
162 
163   @SuppressWarnings("unchecked") // varargs
164   public void testAnd_applyNoArgs() {
165     assertEvalsToTrue(Predicates.and());
166   }
167 
168   @SuppressWarnings("unchecked") // varargs
169   public void testAnd_equalityNoArgs() {
170     new EqualsTester()
171         .addEqualityGroup(Predicates.and(), Predicates.and())
172         .addEqualityGroup(Predicates.and(FALSE))
173         .addEqualityGroup(Predicates.or())
174         .testEquals();
175   }
176 
177   @SuppressWarnings("unchecked") // varargs
178   public void testAnd_applyOneArg() {
179     assertEvalsLikeOdd(Predicates.and(isOdd()));
180   }
181 
182   @SuppressWarnings("unchecked") // varargs
183   public void testAnd_equalityOneArg() {
184     Object[] notEqualObjects = {Predicates.and(NEVER_REACHED, FALSE)};
185     new EqualsTester()
186         .addEqualityGroup(
187             Predicates.and(NEVER_REACHED), Predicates.and(NEVER_REACHED))
188         .addEqualityGroup(notEqualObjects)
189         .addEqualityGroup(Predicates.and(isOdd()))
190         .addEqualityGroup(Predicates.and())
191         .addEqualityGroup(Predicates.or(NEVER_REACHED))
192         .testEquals();
193   }
194 
195   public void testAnd_applyBinary() {
196     assertEvalsLikeOdd(Predicates.and(isOdd(), TRUE));
197     assertEvalsLikeOdd(Predicates.and(TRUE, isOdd()));
198     assertEvalsToFalse(Predicates.and(FALSE, NEVER_REACHED));
199   }
200 
201   @SuppressWarnings("unchecked") // varargs
202   public void testAnd_equalityBinary() {
203     new EqualsTester()
204         .addEqualityGroup(
205             Predicates.and(TRUE, NEVER_REACHED),
206             Predicates.and(TRUE, NEVER_REACHED))
207         .addEqualityGroup(Predicates.and(NEVER_REACHED, TRUE))
208         .addEqualityGroup(Predicates.and(TRUE))
209         .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED))
210         .testEquals();
211   }
212 
213   @SuppressWarnings("unchecked") // varargs
214   public void testAnd_applyTernary() {
215     assertEvalsLikeOdd(Predicates.and(isOdd(), TRUE, TRUE));
216     assertEvalsLikeOdd(Predicates.and(TRUE, isOdd(), TRUE));
217     assertEvalsLikeOdd(Predicates.and(TRUE, TRUE, isOdd()));
218     assertEvalsToFalse(Predicates.and(TRUE, FALSE, NEVER_REACHED));
219   }
220 
221   @SuppressWarnings("unchecked") // varargs
222   public void testAnd_equalityTernary() {
223     new EqualsTester()
224         .addEqualityGroup(
225             Predicates.and(TRUE, isOdd(), NEVER_REACHED),
226             Predicates.and(TRUE, isOdd(), NEVER_REACHED))
227         .addEqualityGroup(Predicates.and(isOdd(), NEVER_REACHED, TRUE))
228         .addEqualityGroup(Predicates.and(TRUE))
229         .addEqualityGroup(Predicates.or(TRUE, isOdd(), NEVER_REACHED))
230         .testEquals();
231   }
232 
233   @SuppressWarnings("unchecked") // varargs
234   public void testAnd_applyIterable() {
235     Collection<Predicate<Integer>> empty = Arrays.asList();
236     assertEvalsToTrue(Predicates.and(empty));
237     assertEvalsLikeOdd(Predicates.and(Arrays.asList(isOdd())));
238     assertEvalsLikeOdd(Predicates.and(Arrays.asList(TRUE, isOdd())));
239     assertEvalsToFalse(Predicates.and(Arrays.asList(FALSE, NEVER_REACHED)));
240   }
241 
242   @SuppressWarnings("unchecked") // varargs
243   public void testAnd_equalityIterable() {
244     new EqualsTester()
245         .addEqualityGroup(
246             Predicates.and(Arrays.asList(TRUE, NEVER_REACHED)),
247             Predicates.and(Arrays.asList(TRUE, NEVER_REACHED)),
248             Predicates.and(TRUE, NEVER_REACHED))
249         .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED))
250         .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED))
251         .testEquals();
252   }
253 
254   @SuppressWarnings("unchecked") // varargs
255   public void testAnd_arrayDefensivelyCopied() {
256     Predicate[] array = {Predicates.alwaysFalse()};
257     Predicate<Object> predicate = Predicates.and(array);
258     assertFalse(predicate.apply(1));
259     array[0] = Predicates.alwaysTrue();
260     assertFalse(predicate.apply(1));
261   }
262 
263   public void testAnd_listDefensivelyCopied() {
264     List<Predicate<Object>> list = newArrayList();
265     Predicate<Object> predicate = Predicates.and(list);
266     assertTrue(predicate.apply(1));
267     list.add(Predicates.alwaysFalse());
268     assertTrue(predicate.apply(1));
269   }
270 
271   public void testAnd_iterableDefensivelyCopied() {
272     final List<Predicate<Object>> list = newArrayList();
273     Iterable<Predicate<Object>> iterable = new Iterable<Predicate<Object>>() {
274       @Override
275       public Iterator<Predicate<Object>> iterator() {
276         return list.iterator();
277       }
278     };
279     Predicate<Object> predicate = Predicates.and(iterable);
280     assertTrue(predicate.apply(1));
281     list.add(Predicates.alwaysFalse());
282     assertTrue(predicate.apply(1));
283   }
284 
285   /*
286    * Tests for all the different flavors of Predicates.or().
287    */
288 
289   @SuppressWarnings("unchecked") // varargs
290   public void testOr_applyNoArgs() {
291     assertEvalsToFalse(Predicates.or());
292   }
293 
294   @SuppressWarnings("unchecked") // varargs
295   public void testOr_equalityNoArgs() {
296     new EqualsTester()
297         .addEqualityGroup(Predicates.or(), Predicates.or())
298         .addEqualityGroup(Predicates.or(TRUE))
299         .addEqualityGroup(Predicates.and())
300         .testEquals();
301   }
302 
303   @SuppressWarnings("unchecked") // varargs
304   public void testOr_applyOneArg() {
305     assertEvalsToTrue(Predicates.or(TRUE));
306     assertEvalsToFalse(Predicates.or(FALSE));
307   }
308 
309   @SuppressWarnings("unchecked") // varargs
310   public void testOr_equalityOneArg() {
311     new EqualsTester()
312         .addEqualityGroup(
313             Predicates.or(NEVER_REACHED), Predicates.or(NEVER_REACHED))
314         .addEqualityGroup(Predicates.or(NEVER_REACHED, TRUE))
315         .addEqualityGroup(Predicates.or(TRUE))
316         .addEqualityGroup(Predicates.or())
317         .addEqualityGroup(Predicates.and(NEVER_REACHED))
318         .testEquals();
319   }
320 
321   public void testOr_applyBinary() {
322     Predicate<Integer> falseOrFalse = Predicates.or(FALSE, FALSE);
323     Predicate<Integer> falseOrTrue = Predicates.or(FALSE, TRUE);
324     Predicate<Integer> trueOrAnything = Predicates.or(TRUE, NEVER_REACHED);
325 
326     assertEvalsToFalse(falseOrFalse);
327     assertEvalsToTrue(falseOrTrue);
328     assertEvalsToTrue(trueOrAnything);
329   }
330 
331   @SuppressWarnings("unchecked") // varargs
332   public void testOr_equalityBinary() {
333     new EqualsTester()
334         .addEqualityGroup(
335             Predicates.or(FALSE, NEVER_REACHED),
336             Predicates.or(FALSE, NEVER_REACHED))
337         .addEqualityGroup(Predicates.or(NEVER_REACHED, FALSE))
338         .addEqualityGroup(Predicates.or(TRUE))
339         .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED))
340         .testEquals();
341   }
342 
343   @SuppressWarnings("unchecked") // varargs
344   public void testOr_applyTernary() {
345     assertEvalsLikeOdd(Predicates.or(isOdd(), FALSE, FALSE));
346     assertEvalsLikeOdd(Predicates.or(FALSE, isOdd(), FALSE));
347     assertEvalsLikeOdd(Predicates.or(FALSE, FALSE, isOdd()));
348     assertEvalsToTrue(Predicates.or(FALSE, TRUE, NEVER_REACHED));
349   }
350 
351   @SuppressWarnings("unchecked") // varargs
352   public void testOr_equalityTernary() {
353     new EqualsTester()
354         .addEqualityGroup(
355             Predicates.or(FALSE, NEVER_REACHED, TRUE),
356             Predicates.or(FALSE, NEVER_REACHED, TRUE))
357         .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED, FALSE))
358         .addEqualityGroup(Predicates.or(TRUE))
359         .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED, TRUE))
360         .testEquals();
361   }
362 
363   @SuppressWarnings("unchecked") // varargs
364   public void testOr_applyIterable() {
365     Predicate<Integer> vacuouslyFalse =
366         Predicates.or(Collections.<Predicate<Integer>>emptyList());
367     Predicate<Integer> troo = Predicates.or(Collections.singletonList(TRUE));
368     /*
369      * newLinkedList() takes varargs. TRUE and FALSE are both instances of
370      * Predicate<Integer>, so the call is safe.
371      */
372     Predicate<Integer> trueAndFalse = Predicates.or(Arrays.asList(TRUE, FALSE));
373 
374     assertEvalsToFalse(vacuouslyFalse);
375     assertEvalsToTrue(troo);
376     assertEvalsToTrue(trueAndFalse);
377   }
378 
379   @SuppressWarnings("unchecked") // varargs
380   public void testOr_equalityIterable() {
381     new EqualsTester()
382         .addEqualityGroup(
383             Predicates.or(Arrays.asList(FALSE, NEVER_REACHED)),
384             Predicates.or(Arrays.asList(FALSE, NEVER_REACHED)),
385             Predicates.or(FALSE, NEVER_REACHED))
386         .addEqualityGroup(Predicates.or(TRUE, NEVER_REACHED))
387         .addEqualityGroup(Predicates.and(FALSE, NEVER_REACHED))
388         .testEquals();
389   }
390 
391   @SuppressWarnings("unchecked") // varargs
392   public void testOr_arrayDefensivelyCopied() {
393     Predicate[] array = {Predicates.alwaysFalse()};
394     Predicate<Object> predicate = Predicates.or(array);
395     assertFalse(predicate.apply(1));
396     array[0] = Predicates.alwaysTrue();
397     assertFalse(predicate.apply(1));
398   }
399 
400   public void testOr_listDefensivelyCopied() {
401     List<Predicate<Object>> list = newArrayList();
402     Predicate<Object> predicate = Predicates.or(list);
403     assertFalse(predicate.apply(1));
404     list.add(Predicates.alwaysTrue());
405     assertFalse(predicate.apply(1));
406   }
407 
408   public void testOr_iterableDefensivelyCopied() {
409     final List<Predicate<Object>> list = newArrayList();
410     Iterable<Predicate<Object>> iterable = new Iterable<Predicate<Object>>() {
411       @Override
412       public Iterator<Predicate<Object>> iterator() {
413         return list.iterator();
414       }
415     };
416     Predicate<Object> predicate = Predicates.or(iterable);
417     assertFalse(predicate.apply(1));
418     list.add(Predicates.alwaysTrue());
419     assertFalse(predicate.apply(1));
420   }
421 
422   /*
423    * Tests for Predicates.equalTo(x).
424    */
425 
426   public void testIsEqualTo_apply() {
427     Predicate<Integer> isOne = Predicates.equalTo(1);
428 
429     assertTrue(isOne.apply(1));
430     assertFalse(isOne.apply(2));
431     assertFalse(isOne.apply(null));
432   }
433 
434   public void testIsEqualTo_equality() {
435     new EqualsTester()
436         .addEqualityGroup(Predicates.equalTo(1), Predicates.equalTo(1))
437         .addEqualityGroup(Predicates.equalTo(2))
438         .addEqualityGroup(Predicates.equalTo(null))
439         .testEquals();
440   }
441 
442   public void testIsEqualToNull_apply() {
443     Predicate<Integer> isNull = Predicates.equalTo(null);
444     assertTrue(isNull.apply(null));
445     assertFalse(isNull.apply(1));
446   }
447 
448   public void testIsEqualToNull_equality() {
449     new EqualsTester()
450         .addEqualityGroup(Predicates.equalTo(null), Predicates.equalTo(null))
451         .addEqualityGroup(Predicates.equalTo(1))
452         .addEqualityGroup(Predicates.equalTo("null"))
453         .testEquals();
454   }
455 
456   /*
457    * Tests for Predicates.isNull()
458    */
459 
460   public void testIsNull_apply() {
461     Predicate<Integer> isNull = Predicates.isNull();
462     assertTrue(isNull.apply(null));
463     assertFalse(isNull.apply(1));
464   }
465 
466   public void testIsNull_equality() {
467     new EqualsTester()
468         .addEqualityGroup(Predicates.isNull(), Predicates.isNull())
469         .addEqualityGroup(Predicates.notNull())
470         .testEquals();
471   }
472 
473   public void testNotNull_apply() {
474     Predicate<Integer> notNull = Predicates.notNull();
475     assertFalse(notNull.apply(null));
476     assertTrue(notNull.apply(1));
477   }
478 
479   public void testNotNull_equality() {
480     new EqualsTester()
481         .addEqualityGroup(Predicates.notNull(), Predicates.notNull())
482         .addEqualityGroup(Predicates.isNull())
483         .testEquals();
484   }
485 
486   public void testIn_apply() {
487     Collection<Integer> nums = Arrays.asList(1, 5);
488     Predicate<Integer> isOneOrFive = Predicates.in(nums);
489 
490     assertTrue(isOneOrFive.apply(1));
491     assertTrue(isOneOrFive.apply(5));
492     assertFalse(isOneOrFive.apply(3));
493     assertFalse(isOneOrFive.apply(null));
494   }
495 
496   public void testIn_equality() {
497     Collection<Integer> nums = ImmutableSet.of(1, 5);
498     Collection<Integer> sameOrder = ImmutableSet.of(1, 5);
499     Collection<Integer> differentOrder = ImmutableSet.of(5, 1);
500     Collection<Integer> differentNums = ImmutableSet.of(1, 3, 5);
501 
502     new EqualsTester()
503         .addEqualityGroup(Predicates.in(nums), Predicates.in(nums),
504             Predicates.in(sameOrder), Predicates.in(differentOrder))
505         .addEqualityGroup(Predicates.in(differentNums))
506         .testEquals();
507   }
508 
509   public void testIn_handlesNullPointerException() {
510     class CollectionThatThrowsNPE<T> extends ArrayList<T> {
511       private static final long serialVersionUID = 1L;
512 
513       @Override public boolean contains(Object element) {
514         Preconditions.checkNotNull(element);
515         return super.contains(element);
516       }
517     }
518     Collection<Integer> nums = new CollectionThatThrowsNPE<Integer>();
519     Predicate<Integer> isFalse = Predicates.in(nums);
520     assertFalse(isFalse.apply(null));
521   }
522 
523   public void testIn_handlesClassCastException() {
524     class CollectionThatThrowsCCE<T> extends ArrayList<T> {
525       private static final long serialVersionUID = 1L;
526 
527       @Override public boolean contains(Object element) {
528         throw new ClassCastException("");
529       }
530     }
531     Collection<Integer> nums = new CollectionThatThrowsCCE<Integer>();
532     nums.add(3);
533     Predicate<Integer> isThree = Predicates.in(nums);
534     assertFalse(isThree.apply(3));
535   }
536 
537   /*
538    * Tests that compilation will work when applying explicit types.
539    */
540   @SuppressWarnings("unused") // compilation test
541   public void testIn_compilesWithExplicitSupertype() {
542     Collection<Number> nums = ImmutableSet.of();
543     Predicate<Number> p1 = Predicates.in(nums);
544     Predicate<Object> p2 = Predicates.<Object>in(nums);
545     // The next two lines are not expected to compile.
546     // Predicate<Integer> p3 = Predicates.in(nums);
547     // Predicate<Integer> p4 = Predicates.<Integer>in(nums);
548   }
549 
550   // enum singleton pattern
551   private enum TrimStringFunction implements Function<String, String> {
552     INSTANCE;
553 
554     @Override
555     public String apply(String string) {
556       return WHITESPACE.trimFrom(string);
557     }
558   }
559 
560   public void testCompose() {
561     Function<String, String> trim = TrimStringFunction.INSTANCE;
562     Predicate<String> equalsFoo = Predicates.equalTo("Foo");
563     Predicate<String> equalsBar = Predicates.equalTo("Bar");
564     Predicate<String> trimEqualsFoo = Predicates.compose(equalsFoo, trim);
565     Function<String, String> identity = Functions.identity();
566 
567     assertTrue(trimEqualsFoo.apply("Foo"));
568     assertTrue(trimEqualsFoo.apply("   Foo   "));
569     assertFalse(trimEqualsFoo.apply("Foo-b-que"));
570 
571     new EqualsTester()
572         .addEqualityGroup(trimEqualsFoo, Predicates.compose(equalsFoo, trim))
573         .addEqualityGroup(equalsFoo)
574         .addEqualityGroup(trim)
575         .addEqualityGroup(Predicates.compose(equalsFoo, identity))
576         .addEqualityGroup(Predicates.compose(equalsBar, trim))
577         .testEquals();
578   }
579 
580   public void assertEqualHashCode(
581       Predicate<? super Integer> expected, Predicate<? super Integer> actual) {
582     assertEquals(actual + " should hash like " + expected, expected.hashCode(), actual.hashCode());
583   }
584 
585   public void testHashCodeForBooleanOperations() {
586     Predicate<Integer> p1 = Predicates.isNull();
587     Predicate<Integer> p2 = isOdd();
588 
589     // Make sure that hash codes are not computed per-instance.
590     assertEqualHashCode(
591         Predicates.not(p1),
592         Predicates.not(p1));
593 
594     assertEqualHashCode(
595         Predicates.and(p1, p2),
596         Predicates.and(p1, p2));
597 
598     assertEqualHashCode(
599         Predicates.or(p1, p2),
600         Predicates.or(p1, p2));
601 
602     // While not a contractual requirement, we'd like the hash codes for ands
603     // & ors of the same predicates to not collide.
604     assertTrue(Predicates.and(p1, p2).hashCode() != Predicates.or(p1, p2).hashCode());
605   }
606 
607   private static void assertEvalsToTrue(Predicate<? super Integer> predicate) {
608     assertTrue(predicate.apply(0));
609     assertTrue(predicate.apply(1));
610     assertTrue(predicate.apply(null));
611   }
612 
613   private static void assertEvalsToFalse(Predicate<? super Integer> predicate) {
614     assertFalse(predicate.apply(0));
615     assertFalse(predicate.apply(1));
616     assertFalse(predicate.apply(null));
617   }
618 
619   private static void assertEvalsLikeOdd(Predicate<? super Integer> predicate) {
620     assertEvalsLike(isOdd(), predicate);
621   }
622 
623   private static void assertEvalsLike(
624       Predicate<? super Integer> expected,
625       Predicate<? super Integer> actual) {
626     assertEvalsLike(expected, actual, 0);
627     assertEvalsLike(expected, actual, 1);
628     assertEvalsLike(expected, actual, null);
629   }
630 
631   private static <T> void assertEvalsLike(
632       Predicate<? super T> expected,
633       Predicate<? super T> actual,
634       T input) {
635     Boolean expectedResult = null;
636     RuntimeException expectedRuntimeException = null;
637     try {
638       expectedResult = expected.apply(input);
639     } catch (RuntimeException e) {
640       expectedRuntimeException = e;
641     }
642 
643     Boolean actualResult = null;
644     RuntimeException actualRuntimeException = null;
645     try {
646       actualResult = actual.apply(input);
647     } catch (RuntimeException e) {
648       actualRuntimeException = e;
649     }
650 
651     assertEquals(expectedResult, actualResult);
652     if (expectedRuntimeException != null) {
653       assertNotNull(actualRuntimeException);
654       assertEquals(
655           expectedRuntimeException.getClass(),
656           actualRuntimeException.getClass());
657     }
658   }
659 }
660